\chapter{Estudo do SQLServerResultSet}
\label{ap:msjdbc}

Aquando da criação do objecto statement é definido o tipo de result set que é criado. Esse tipo determina o modo como os dados são carregados do servidor; podem ser usados cursores de servidor ou não, podem ser carregados todos os dados de uma só vez ou podem ser carregados conforme a aplicação vai os vai requisitando.

Nesta secção é apresentado um estudo da classe SQLServerResultSet, que corresponde à classe do driver da Microsoft que implementa a interface java.sql.ResultSet. O estudo concentra-se no modo de interacção do ResultSet com o SQL Server.

\section{Cursores no SQL Server}

As operações numa base de dados relacional actuam sobre um conjunto de linhas que satisfazem a cláusula WHERE de uma statement, no entanto muitas aplicações precisam de trabalhar com blocos mais pequenos ou até com uma linha de cada vez. Os cursores fornecem esse mecanismo, permitindo \cite{CursorsDatabaseEngine}:
\begin{itemize}
  \item Posicionamento numa linha específica.
  \item Acesso a uma linha ou um bloco de linhas a partir da localização actual no result set.
  \item Modificar (actualizar, remover) linhas.
  \item Diferentes níveis de visibilidade às modificações realizadas por outros no result set.
  \item Acesso ao result set a partir de Transact-SQL em scripts, stored procedures e triggers.
\end{itemize}

\subsection{Fetching e Scrolling}
\label{sec:fetchscroll}

A operação de obter uma linha a partir do cursor designa-se por \emph{fetch}. Um cursor é classificado quanto ao tipo de fetch que suporta \cite{FetchingScrolling}:
\begin{itemize}
  \item Forward-only \\
  As linhas são obtidas sequencialmente da primeira até à última.
  \item Scrollable \\
  Qualquer linha pode ser obtida em qualquer direcção.
\end{itemize}

Um cursor Forward-only suporta a seguinte operação de fetch:
\begin{itemize}
  \item FETCH NEXT \\
  Obtém a próxima linha.
\end{itemize}

Um cursor Scrollalble suporta as seguintes operações de fetch:
\begin{itemize}
  \item FETCH NEXT \\
  Obtém a próxima linha.
  \item FETCH FIRST \\
  Obtém a primeira linha.
  \item FETCH PRIOR \\
  Obtém a linha anterior.
  \item FETCH LAST \\
  Obtém a última linha.
  \item FETCH ABSOLUTE n \\
  Obtém a linha \emph{n} a partir da primeira linha.
  \item FETCH RELATIVE n \\
  Obtém a linha \emph{n} a partir da linha actual.
\end{itemize}

\subsection{Concorrência}

O SQL Server suporta 4 tipos de concorrência \cite{CursorConcurrencyDatabaseEngine}:
\begin{itemize}
  \item READ\_ONLY \\
  A actualização usando o cursor não é permitida e não são obtidos locks nas linhas do result set.

  \item OPTIMISTIC WITH VALUES \\
  Não são obtidos locks nas linhas. Quando uma actualização ocorre os valores actuais das colunas da linha são comparados com os valores anteriormente carregados, se forem iguais procede-se à actualização, caso contrário é lançado um erro.

  \item OPTIMISTIC WITH ROW VERSIONING \\
  A tabela a actualizar tem que possuir uma coluna do tipo timestamp. Numa actualização valores de timestamp são comparados para determinar se a linha foi alterada ou não por outros, e em caso negativo os novos valores são guardados.

  \item SCROLL LOCKS \\
  O cursor lê a linha obtendo um update lock. Se o cursor for aberto no decorrer de uma transacção o lock mantém-se até ocorrer um commit ou um roll-back. Se o cursor for aberto fora de uma transacção o lock da linha é liberto quando for obtida uma outra linha.
\end{itemize}

\subsection{Tipos de cursor}

O SQL Server suporta os seguintes tipos de cursor \cite{CursorTypesDatabaseEngine}:
\begin{description}
  \item[Forward-only] \cite{ForwardOnlyCursors} \hfill \\
  Não suporta scrolling, as linhas são obtidas sequencialmente da primeira para a última. As linhas só são carregadas quando são pedidas. As modificações provenientes das operações de inserção, actualização e remoção, realizadas pelo próprio ou por outros são visíveis. O SQL Server implementa uma versão designada por Fast Forward-only, com optimização de desempenho \cite{FastForwardOnlyCursors}.
    
  \item[Static] \cite{StaticCursors} \hfill \\
  Quando o cursor é aberto é criada uma cópia do result set na base de dados {\bf tempdb}. Uma vez que trabalha com uma cópia, através deste tipo de cursor as modificações não são visíveis. Também é conhecido como cursor insensitive e cursor snapshot.
  
  \item[Keyset-driven] \cite{KeysetCursors} \hfill \\ 
  São usadas chaves para aceder às linhas da tabela. A tabela tem que possuir uma ou mais linhas que permitam identificar unicamente uma linha. O keyset (conjunto de chaves) é criado como uma tabela na base de dados {\bf tempdb}.
  As modificações, próprias ou externas, nas colunas que não são chave são visíveis, mas as inserções externas não são visíveis.

  \item[Dynamic] \cite{DynamicCursors} \hfill \\
  Todas as modificações são visíveis. Os valores e a ordem das linhas pode ser alterada em cada fetch. Este tipo de cursor é o que tem mais baixo desempenho, principalmente para maiores quantidades de dados, e têm também problemas de concorrência porque em cada fetch o result set é reconstruído, e por isso em geral deve-se evitar a sua utilização \cite{Vieira2006}. No entanto, para quantidades de dados pequenas  o result set trabalha a partir da RAM, senso nesta situação mais rápido do que o keyset, que trabalha a partir do disco (este utiliza uma tabela temporária na tempdb) \cite{Vieira2006}.
\end{description}

\section{Tipos de cursor por result set}

As características requisitadas ao result set determinam a interacção que o SQLServerResultSet tem com o servidor. A Tabela \ref{tab:msdrivercursortypes} mostra que tipo de cursor de servidor é criado para cada característica do result set \cite{UnderstandingCursorTypes}. A API JDBC permite definir os requisitos do result set quanto à navegabilidade (forward-only ou scrollable) e à concorrência (actualizável ou só de leitura), mas o SQLServerResultSet suporta ainda mais uma característica, buffering, que é indicada na coluna com o mesmo nome na Tabela \ref{tab:msdrivercursortypes} e explicada na secção \ref{sec:adaptivebuffering}.

\begin{center}
  \scriptsize
  \begin{longtable}{|p{3.6cm}|p{1.2cm}|p{2.1cm}|p{1.4cm}|p{4cm}|}
  \caption{Tipos de cursor suportados pelo driver}
  \label{tab:msdrivercursortypes}
  \\ \hline
  \head{Tipo} & \head{Cursor} & \head{Característica} & \head{Buffering} & \head{Descrição}
  \\ \hline
  \endhead
  \input{appendices/msdrivercursortypes}
  \\ \hline
  \end{longtable}
\end{center}

O SQLServerResultSet para além de suportar os tipos de result set definidos pela interface \emph{ResultSet}, adiciona alguns tipos que permitem requisitar explicitamente tipos específicos que existem no SQL Server, tanto ao nível da navegação (forward-only, scrollable), como ao nível do tipo de concorrência \cite{SQLServerResultSetMembers}:

\begin{itemize}
  \item CONCUR\_SS\_OPTIMISTIC\_CC \\
  Leitura e escrita com concorrência optimística (row versioning) e sem locks de linha.

  \item CONCUR\_SS\_OPTIMISTIC\_CCVAL \\
  Leitura e escrita com concorrência optimística (values) e sem locks de linha.

  \item CONCUR\_SS\_SCROLL\_LOCKS \\
  Leitura e escrita com concorrência optimística e com locks de linha.

  \item TYPE\_SS\_DIRECT\_FORWARD\_ONLY \\
  Cursor do tipo \emph{fast forward-only}, só de leitura.

  \item TYPE\_SS\_SCROLL\_DYNAMIC \\
  Cursor do tipo \emph{dynamic}.

  \item TYPE\_SS\_SCROLL\_KEYSET \\
  Cursor do tipo \emph{keyset}.

  \item TYPE\_SS\_SCROLL\_STATIC \\
  Cursor do tipo \emph{static}.

  \item TYPE\_SS\_SERVER\_CURSOR\_FORWARD\_ONLY \\
  Cursor do tipo \emph{fast forward-only}, só de leitura.
\end{itemize}

\section{Adaptive Buffering}
\label{sec:adaptivebuffering}

O \emph{adaptive buffering} é uma funcionalidade introduzida no Microsoft SQL Server 2005 JDBC Driver versão 1.2, que tem como finalidade o carregamento de grandes quantidades de dados sem a necessidade de utilizar cursores do servidor \cite{ADAPTIVEBUFFERING}.

O que isto significa é que existem dois modos de carregamento de dados: {\bf adaptive} e {\bf full}. No modo adaptive é carregada a menor quantidade possível de dados, enquanto que no modo full todo o result set é lido do servidor em \emph{run time}.

O acesso a esta funcionalidade é realiza pela utilização do método \texttt{setResponseBuffering} \cite{setResponseBuffering} da classe \emph{SQLServerStatement} \cite{SQLServerStatement}, que recebe uma String (full ou adaptive) que indica o modo desejado. 

A classe \emph{SQLServerStatement} é a implementação da interface \texttt{java.sql.Statement}.

A principal motivação é diminuir a quantidade de memória utilizada pela aplicação, e até evitar situações em que a memória esgota e é lançado o erro {\bf OutOfMemoryError}, quando a aplicação JDBC trabalha com \emph{queries} que produzem resultados muito grandes.
